﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Compilex.Syntatic
{
    public enum TypeValue
    {
        intex,
        boolex,
        cadeiex,
        carex,
        userDefined
    }

    public class SymbolType
    {
        public TypeValue TypeValue { get; set; }
        public string UserDefinedTypeName { get; set; }
        public int SizeBytes
        {
            get
            {
                return 2;
            }
        }
        public SymbolType(TypeValue type)
        {
            this.TypeValue = type;
            if (type == TypeValue.userDefined)
                throw new InternalSyntaticException("Um tipo definido pelo usuario precisa do nome");
        }

        public SymbolType(SymbolType type)
        {
            this.TypeValue = type.TypeValue;
            this.UserDefinedTypeName = type.UserDefinedTypeName;
        }

        public SymbolType(string userDefinedType)
        {
            this.TypeValue = TypeValue.userDefined;
            this.UserDefinedTypeName = userDefinedType;
        }


        public static SymbolType FromString(string type)
        {
            switch (type)
            {
                case "intex":
                    return new SymbolType(TypeValue.intex);
                case "boolex":
                    return new SymbolType(TypeValue.boolex);
                case "carex":
                    return new SymbolType(TypeValue.carex);
                case "cadeiex":
                    return new SymbolType(TypeValue.cadeiex);
                default:
                    return new SymbolType(type);
            }
        }

        public override string ToString()
        {
            switch (this.TypeValue)
            {
                case TypeValue.intex:
                    return "intex";
                case TypeValue.boolex:
                    return "boolex";
                case TypeValue.cadeiex:
                    return "cadeiex";
                case TypeValue.carex:
                    return "carex";
                case TypeValue.userDefined:
                    return this.UserDefinedTypeName;
                default:
                    throw new InternalSyntaticException("Valor de tipo inválido");
            }
        }

        // override object.Equals
        public override bool Equals(object obj)
        {
            if (obj == null || GetType() != obj.GetType())
            {
                return false;
            }

            SymbolType otherType = (SymbolType)obj;
            if (otherType.TypeValue != this.TypeValue)
                return false;
            else if (otherType.TypeValue == TypeValue.userDefined)
                return otherType.UserDefinedTypeName == this.UserDefinedTypeName;
            return true;
        }

        // override object.GetHashCode
        public override int GetHashCode()
        {
            if (this.TypeValue != TypeValue.userDefined)
            {
                return this.TypeValue.GetHashCode();
            }
            else
            {
                return this.UserDefinedTypeName.GetHashCode();
            }
        }

        public static bool operator ==(SymbolType a, SymbolType b)
        {
            // If both are null, or both are same instance, return true.
            if (System.Object.ReferenceEquals(a, b))
            {
                return true;
            }

            // If one is null, but not both, return false.
            if (((object)a == null) || ((object)b == null))
            {
                return false;
            }


            return a.Equals(b);
        }
        public static bool operator !=(SymbolType a, SymbolType b)
        {
            return !(a == b);
        }
    }
}
